package org.fve.ws;


import java.net.UnknownHostException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Hashtable;
import java.util.Random;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.servlet.http.HttpServletRequest;
import javax.sip.InvalidArgumentException;
import javax.sip.ObjectInUseException;
import javax.sip.PeerUnavailableException;
import javax.sip.SipException;
import javax.sip.TransportNotSupportedException;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketHandler;
import org.fve.sip.SipInvite;
import org.fve.sip.SipRegister;
import org.fve.user.User;

import fve.Utils_;

import ws.bbdd.bbdd;

	public class WebSocketServerHandler extends WebSocketHandler {

		public final static Set<ChatWebSocket> webSockets = new CopyOnWriteArraySet<ChatWebSocket>();

		public WebSocket doWebSocketConnect(HttpServletRequest request,
				String protocol) {			
			return new ChatWebSocket();
		}

		public class ChatWebSocket implements WebSocket.OnTextMessage {
			
			bbdd bd = new bbdd();
			private WebsocketTX ws_TX = new WebsocketTX();
			public User user;		
			private Connection conn;

			@SuppressWarnings("unchecked")
			public void onOpen(Connection connection) {
				Utils_.tbuserwebsocket=(Hashtable<String, Connection>) getServer().getAttribute("tbuserwebsocket");
				Utils_.tbuserConn=(Hashtable<String, Connection>) getServer().getAttribute("tbuserConn");
				Utils_.tbConnuser=(Hashtable<Connection,String>) getServer().getAttribute("tbConnuser");
				
				// Client (Browser) WebSockets has opened a connection.
				// 1) Store the opened connection
				conn = connection;				
				System.out.println("WebSocketServerHandler-->onOpen: "+connection);
				// 2) Add ChatWebSocket in the global list of ChatWebSocket
				// instances
				// instance.
				webSockets.add(this);
				Thread t = new Thread( new Runnable() {					
					public void run(){
						Random WebNum = new Random(10000000);
						String idsesion = WebNum.toString().substring(WebNum.toString().indexOf("@"));
						while(Utils_.tbuserwebsocket.containsKey(idsesion)){
							WebNum = new Random(10000000);
							idsesion = WebNum.toString().substring(WebNum.toString().indexOf("@"));
						}
						
						user = new User("null", Utils_.CheckPort(), "null", Utils_.NON_SIP_STATE,conn,idsesion,"null",Utils_.getMyIP());
						System.out.println("WebSocketServerHandler-->User settings OK");
						Utils_.tbuserwebsocket.put(user.getIdSesion() , user.getConnection());
						//Control errores primera vez, para que haya un valor en la hastable que se pueda borrar
						Utils_.tbuserConn.put(user.getName(),user.getConnection());
						Utils_.tbConnuser.put(user.getConnection(),user.getName());
						
						//send to user the SessionId
						ws_TX.sendToUser(user.getConnection(),"IDSESION#"+user.getIdSesion(),Utils_.log);							
						System.out.println("WebSocketServerHandler-->onOpen-->sendMessage: "+"IDSESION#"+idsesion);			
					
					}

				});
				t.start();
				System.out.println("WebSocketServerHandler-->******IdSession & Port...Thread Started!******");
				
				}			

			
			
			
			public void onMessage(String message) {	
				if(user.getName()!="null"){
				Utils_.log.WriteLog("WebSocketServerHandler-->Message recieved by "+user.getName()+":"+ message);
				}
				String enviar="";
				String[] recibido = message.split("#");
		        if(message.indexOf("idUsuario#")!=-1){		//Proceso de Login
		        	
					try { 		      
						user.setName(this.getValuefromStringArray(recibido, "idUsuario"));
						user.setPassw(this.getValuefromStringArray(recibido, "PASS"));
						user.setSipUser("sip:"+user.getName().toLowerCase()+"@"+Utils_.SIP_ADDRESS);	
						//log = new logger(user.getName());
						enviar = bd.consultaBBDD("10",user.getName()+"#"+user.getConnection().toString()+"#1"+"#"+user.getPassw());
							if(enviar.equals("USERLOGIN#TRUE")){
								Utils_.tbuserConn.put(user.getName(), user.getConnection());
								Utils_.tbConnuser.put(user.getConnection(),user.getName());							
								ws_TX.sendToUser(user.getConnection(),enviar,Utils_.log);								
								
								//try to connect to ServerSip
								//Send Register															
								try {
									if(user.GetSipRegister()==null){
										SipRegister register = new SipRegister(user);
										user.setSipRegister(register);
									}
									user.GetSipRegister().sendREGISTER(user.getName().toLowerCase(), "null");									
									bd.consultaBBDD("9",user.getConnection()+"#"+Utils_.REGISTER_STATE+"#"+user.getPort()+"#"+user.GetSipRegister().getPort()+"#"+user.GetSipRegister().getExpirerTime());
																		
								} catch (PeerUnavailableException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (TransportNotSupportedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (ObjectInUseException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (UnknownHostException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (InvalidArgumentException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (TooManyListenersException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (ParseException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (SipException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}		
								
											    								    				
							}else{
								ws_TX.sendToUser(user.getConnection(),"USERLOGIN#FALSE",Utils_.log);
							}
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 	
				}else if(message.indexOf("FRIENDSONLINE")!=-1){					//Proceso de Consulta sobre usuarios online
					try {					
						enviar ="FRIENDSONLINE#"+ bd.consultaBBDD("4", user.getName());						
						String[] Friendstosend =enviar.split("#");
						String[] messageforfriends = new String[Friendstosend.length];						
						for(int i=0;i<Friendstosend.length;i++){
							messageforfriends[i]="FRIENDSONLINE#"+ bd.consultaBBDD("4", Friendstosend[i]);
						}
						ws_TX.sendTofriendsUsers(messageforfriends,Friendstosend,Utils_.tbConnuser,Utils_.log);
						ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
					
				}else if(message.indexOf("SIGNIN")!=-1){				   //Proceso de Consulta sobre usuarios
					
					try {						
						user.setName(this.getValuefromStringArray(recibido, "SIGNIN"));
						user.setPassw(this.getValuefromStringArray(recibido, "PASS"));
						user.setSipUser("sip:"+user.getName().toLowerCase()+"@"+Utils_.SIP_ADDRESS);
						
						enviar = bd.consultaBBDD("1", user.getName()+"#"+user.getConnection().toString()+"#1"+"#"+user.getPassw());
						//log = new logger(user.getName());						
						if(enviar.equals("SIGNIN#TRUE")){
							Utils_.tbuserConn.put( user.getName(), user.getConnection());
							Utils_.tbConnuser.put( user.getConnection(),user.getName());
							ws_TX.sendToUser(user.getConnection(), "USERLOGIN#TRUE",Utils_.log);
						}else{
							ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);	
						}
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
					
				}else if(message.indexOf("FRIENDS#")!=-1){					//Proceso de Consulta sobre amigos
											
					try {
						//String user=this.getValuefromStringArray(recibido, "FRIENDS");
						enviar = bd.consultaBBDD("5", user.getName());		        			
						ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
					
				}else if(message.indexOf("FRIENDWITH#")!=-1){				//Proceso de crear amigos
										
					try {
						String friendname=this.getValuefromStringArray(recibido, "FRIENDWITH");
						//String from=this.getValuefromStringArray(recibido, "FROM");
						bd.consultaBBDD("6", user.getName()+"#"+friendname);				//guardar amigo								//
						enviar = bd.consultaBBDD("5", recibido[3]); 		//enviamos amigos de nuevo		        			
						ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
					
				}else if(message.indexOf("UNFRWITH#")!=-1){					//Proceso de crear amigos
					 						
					try {
						String friendname=this.getValuefromStringArray(recibido, "UNFRWITH");
						//String from=this.getValuefromStringArray(recibido, "FROM");
						bd.consultaBBDD("7", user.getName()+"#"+friendname);				//guardar amigo								//
						enviar = bd.consultaBBDD("5", user.getName()); 				//enviamos amigos de nuevo		        			
						ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
					
				}else if(message.indexOf("INVITE-OK#")!=-1){				//Proceso de llamada-ACK		        		     		
						String friendname=this.getValuefromStringArray(recibido, "INVITE-OK");		        			
						Connection friendconn=Utils_.tbuserConn.get(friendname);
						ws_TX.sendToUser(friendconn, message,Utils_.log);        		
					
				}else if(message.indexOf("SOUT#")!=-1){						//Proceso de cerrar sesion
					      				        		
						try {      
							//String user=this.getValuefromStringArray(recibido, "SOUT");
							bd.consultaBBDD("2",user.getConnection().toString()+"#state#0");//modificamos estado
							Utils_.tbuserConn.remove(user.getName());	    	//borramos de la hastable
							Utils_.tbConnuser.remove( user.getConnection());
							Utils_.tbuserwebsocket.remove(user.getIdSesion());
							enviar ="FRIENDSONLINE#"+ bd.consultaBBDD("4", user.getName());						
							String[] Friendstosend =enviar.split("#");
							String[] messageforfriends = new String[Friendstosend.length];						
							for(int i=0;i<Friendstosend.length;i++){
								messageforfriends[i]="FRIENDSONLINE#"+ bd.consultaBBDD("4", Friendstosend[i]);
							}
							ws_TX.sendTofriendsUsers(messageforfriends,Friendstosend,Utils_.tbConnuser,Utils_.log);			 
							//  log.WriteLog("DATAUSERSON#"+enviar);
						} catch (SQLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}	
					
				}else if(message.indexOf("SEARCH#")!=-1){	//Proceso de cerrar sesion
							        			
						try {      
							String busqueda=this.getValuefromStringArray(recibido, "SEARCH");
							if(busqueda.equals("")){
								enviar = "SEARCH#";
							}else{
							enviar = bd.consultaBBDD("8",busqueda);//modificamos estado	
							}		        				
							ws_TX.sendToUser(user.getConnection(), enviar,Utils_.log);	    							 
						
						} catch (SQLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}       	
					
				}else if(message.indexOf("INVITE#")!=-1){	//Proceso de llamada  
						if(message.indexOf("MOBILE")!=-1){	//Movil							
							if(user.GetSipInvite()==null){
								SipInvite invite = new SipInvite(user, user.getPort());	
								user.setSipInvite(invite);
							}
								String friendname=this.getValuefromStringArray(recibido, "INVITE");
							try {
								user.GetSipInvite().sendINVITE(friendname.toLowerCase(), user);
							} catch (ParseException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (InvalidArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (SipException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}else{								//Web
							String friendname=this.getValuefromStringArray(recibido, "INVITE");
							Connection friendconn=Utils_.tbuserConn.get(friendname);
							ws_TX.sendToUser(friendconn, message,Utils_.log);
						}
					
				}else if(message.indexOf("BYE#")!=-1){		//Proceso de Finalizar llamada  
					
						String friendname=this.getValuefromStringArray(recibido, "BYE");
						Connection friendconn=Utils_.tbuserConn.get(friendname);
						ws_TX.sendToUser(friendconn, message,Utils_.log);
					
				}else if(message.indexOf("MESSAGE#")!=-1){	//Proceso de paso de mensajes  
						String friendname = this.getValuefromStringArray(recibido, "TO");
						Connection friendconn=Utils_.tbuserConn.get(friendname);
						ws_TX.sendToUser(friendconn, message,Utils_.log);		        			
					
				}
		        
		       	

			}
			
			private String getValuefromStringArray(String[] fragmento,String Value){
				for(int i=0; i<fragmento.length;i++){
					if(fragmento[i].equals(Value)){
						return fragmento[i+1];
					}
				}				
				return null;				
			}			
			

			public void onClose(int closeCode, String message) {
					//log.WriteLog("Closed message:"+message);
				//String name=tbConnuser.get(this.connection);
				if(user.getName()!="null"){
				Utils_.log.WriteLog("Closed Connection:"+user.getConnection());
				}
				String enviar="";
				try {
					bd.consultaBBDD("2",user.getConnection().toString()+"#state#0");				//modificamos estado	
					
					Utils_.tbuserConn.remove(user.getName());	    	//borramos de la hastable
					Utils_.tbConnuser.remove( user.getConnection());
					Utils_.tbuserwebsocket.remove(user.getIdSesion());
				enviar ="FRIENDSONLINE#"+ bd.consultaBBDD("4", user.getName());						
				String[] Friendstosend =enviar.split("#");
				String[] messageforfriends = new String[Friendstosend.length];						
				for(int i=0;i<Friendstosend.length;i++){
					messageforfriends[i]="FRIENDSONLINE#"+ bd.consultaBBDD("4", Friendstosend[i]);
				}
				ws_TX.sendTofriendsUsers(messageforfriends,Friendstosend,Utils_.tbConnuser,Utils_.log);
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				webSockets.remove(this);
				if(user.GetSipRegister()!=null){
					user.GetSipRegister().CloseListener();
					user.setSipRegister(null);
				}
				if(user.GetSipInvite()!=null){
					user.GetSipInvite().CloseListener();
					user.setSipInvite(null)  ;
				}
				//this.sendToAllUsers("FRIENDSONLINE#"+enviar);	   		//enviamos de nuevo users 
				//log.WriteLog("WebSocketServerHandler-->Message send to "+usersend+":"+"FRIENDSONLINE#"+enviar);								
				
			}
			
		}
		
}
